package com.zrl.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zrl.project.common.ErrorCode;
import com.zrl.project.common.UserHolder;
import com.zrl.project.constant.CommonConstant;
import com.zrl.project.exception.BusinessException;
import com.zrl.project.model.VO.qustionVO.*;
import com.zrl.project.model.entity.*;
import com.zrl.project.service.*;
import com.zrl.project.mapper.QuestionMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author 13168
* @description 针对表【question(题目表)】的数据库操作Service实现
* @createDate 2023-03-31 15:10:00
*/
@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question>
    implements QuestionService{

    @Resource
    private QuestionTagsService questionTagsService;

    @Resource
    private QuestionItemService questionItemService;

    @Resource
    private QuestionAnswerService questionAnswerService;

    @Resource
    private CommentService commentService;

    @Resource
    private UserService userService;

    @Resource
    private TagsService tagsService;

    @Resource
    private QuestionLikeService questionLikeService;

    @Override
    @Transactional
    public Boolean addQuestion(AddQuestionParamVO addQuestionParam) {

        //查询题目类型
        Integer questionType = addQuestionParam.getQuestionType();

        //保存题目基本信息（单选题答案直接存入）
        Question question = new Question();
        BeanUtils.copyProperties(addQuestionParam,question);
        boolean save = save(question);
        if (!save){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"添加失败");
        }


        //获得保存后的题目id
        Long id = question.getId();

        //保存题目标签
        List<Integer> tags = addQuestionParam.getTags();
        List<QuestionTags> tagsList = tags.stream().map(tag -> {
            QuestionTags questionTags = new QuestionTags();
            questionTags.setQuestionId(id);
            questionTags.setTagsId(tag);
            return questionTags;
        }).collect(Collectors.toList());
        boolean b = questionTagsService.saveBatch(tagsList);
        if (!b){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"上传题目失败");
        }

        //简答题
        if (questionType == 0){

            return true;
        }


        //其他题目
        //单选题
        if (questionType == 1){
            SingleOptionAndAnswerVO singleParams = addQuestionParam.getSingleParams();
            if (singleParams == null){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"题目选项不能为空");
            }
            //添加题目答案
            String answer = singleParams.getAnswer();
            QuestionAnswer questionAnswer = new QuestionAnswer();
            questionAnswer.setQuestionId(id);
            questionAnswer.setQuestionItemNum(answer);
            boolean saveAnswer = questionAnswerService.save(questionAnswer);
            if (!saveAnswer){
                throw new BusinessException(ErrorCode.OPERATION_ERROR,"添加失败");
            }
            //添加题目选项
            return addQuestionItem(id, singleParams.getOptions());
        }


        MultipleOptionAndAnswerVO multipleParams = addQuestionParam.getMultipleParams();
        if (multipleParams == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目选项不能为空");
        }
        //添加题目答案
        List<String> answerList = multipleParams.getAnswer();
        List<QuestionAnswer> questionAnswerList = answerList.stream().map(answer -> {
            QuestionAnswer questionAnswer = new QuestionAnswer();
            questionAnswer.setQuestionId(id);
            questionAnswer.setQuestionItemNum(answer);
            return questionAnswer;
        }).collect(Collectors.toList());
        boolean saveBatch = questionAnswerService.saveBatch(questionAnswerList);
        if (!saveBatch) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "添加题目失败");
        }

        //添加选项
        return addQuestionItem(id, multipleParams.getOptions());

    }

    
    @Override
    public List<QuestionWithUserInfoVO> queryQuestionsWithUserInfo(SearchQuestionParamVO question) {

        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Question::getCreateTime);

        Long userId = question.getUserId();
        //搜索指定用户的题目
        if (question.getUserId() != null){
            queryWrapper.eq(Question::getUserId,userId);
            List<QuestionWithUserInfoVO> QuestionAndUserInfoVOList = list(queryWrapper)
                    .stream()
                    .map(this::getQuestionWithUserInfoVO)
                    .collect(Collectors.toList());

            return QuestionAndUserInfoVOList.stream()
                    .sorted(Comparator.comparing(QuestionWithUserInfoVO::getCommentsCount).reversed())
                    .sorted(Comparator.comparing(QuestionWithUserInfoVO::getLikes).reversed())
                    .collect(Collectors.toList());

        }


        String order = question.getOrder();
        if (CommonConstant.GOOD.equals(order)){
            queryWrapper.eq(Question::getPriority,CommonConstant.TOP);
        }

        //通过题目内容查询
        String content = question.getTitle();
        if (StringUtils.isNotBlank(content)) {
            //查询内容和标题与输入内容相匹配的question
            queryWrapper.and(questionLambdaQueryWrapper -> {
                questionLambdaQueryWrapper.like(Question::getTitle, content)
                .or()
                .like(Question::getAnalysis,content)
                .or()
                .like(Question::getContent,content);
            });

        }

        //通过标签查询
        List<Integer> tags = question.getTags();
        if (tags!=null && !tags.isEmpty()){
            List<List<Long>> questionIdList = new ArrayList<>();
            tags.forEach((tagId)->{
                LambdaQueryWrapper<QuestionTags> questionTagsLambdaQueryWrapper = new LambdaQueryWrapper<>();
                questionTagsLambdaQueryWrapper.eq(QuestionTags::getTagsId,tagId);
                List<Long> questionIdList1 = questionTagsService.list(questionTagsLambdaQueryWrapper)
                        .stream().map(QuestionTags::getQuestionId).collect(Collectors.toList());
                questionIdList.add(questionIdList1);
            });

            List<Long> questionIds = questionIdList.get(0);
            questionIdList.forEach(questionIds::retainAll);

            if (questionIds.isEmpty()){
                queryWrapper.eq(Question::getId,-1);
            }else {
                questionIds.forEach(id->{
                    queryWrapper.and(questionLambdaQueryWrapper -> {
                        questionLambdaQueryWrapper.eq(Question::getId,id);
                        if (questionIds.indexOf(id) != questionIds.size()){
                            questionLambdaQueryWrapper.or();
                        }
                    });
                });
            }
        }

        //通过题目类型查询
        Integer questionType = question.getQuestionType();
        if (questionType != null){
            queryWrapper.and(questionLambdaQueryWrapper -> {
                questionLambdaQueryWrapper.eq(Question::getQuestionType,questionType);
            });
        }

        //通过难度查询
        Integer difficult = question.getDifficult();
        if (difficult != null){
            queryWrapper.and(questionLambdaQueryWrapper -> {
                questionLambdaQueryWrapper.eq(Question::getDifficult,difficult);
            });
        }


        List<QuestionWithUserInfoVO> questionWithUserInfoVOS = list(queryWrapper)
                .stream()
                .map(this::getQuestionWithUserInfoVO)
                .collect(Collectors.toList());

        if (CommonConstant.HOT.equals(order)){
            return questionWithUserInfoVOS.stream()
                    .sorted(Comparator.comparing(QuestionWithUserInfoVO::getCommentsCount).reversed())
                    .sorted(Comparator.comparing(QuestionWithUserInfoVO::getLikes).reversed())
                    .collect(Collectors.toList());
        }

        return questionWithUserInfoVOS;
    }


    private QuestionWithUserInfoVO getQuestionWithUserInfoVO(Question question) {

        //查询评论数量
        LambdaQueryWrapper<Comment> commentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        commentLambdaQueryWrapper.eq(Comment::getQuestionId,question.getId());
        long commentCount = commentService.count(commentLambdaQueryWrapper);

        //查询喜欢数量
        LambdaQueryWrapper<QuestionLike> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(QuestionLike::getQuestionId,question.getId());
        long likesCount = questionLikeService.count(queryWrapper);

        List<Tags> tags = getTagsList(question);
        List<String> stringList = tags.stream().map(Tags::getContent).collect(Collectors.toList());


        //根据用户id查询用户信息
        Long userId = question.getUserId();
        User user = userService.getById(userId);
        //将用户名称和用户头像,评论数量，点赞数量，题目标签加入到QuestionWithUserInfoVO中
        QuestionWithUserInfoVO questionWithUserInfoVO = new QuestionWithUserInfoVO();
        BeanUtils.copyProperties(question,questionWithUserInfoVO);
        questionWithUserInfoVO.setUserName(user.getUserName());
        questionWithUserInfoVO.setUserAvatar(user.getUserAvatar());
        questionWithUserInfoVO.setCommentsCount(commentCount);
        questionWithUserInfoVO.setLikes(likesCount);
        questionWithUserInfoVO.setTags(stringList);

        return questionWithUserInfoVO;
    }


    @Override
    @Transactional
    public QuestionDetailVO getQuestionDetail(Long id) {

        QuestionDetailVO questionDetailVO = new QuestionDetailVO();

        //查询题目基本信息
        Question question = getById(id);
        //查询用户信息以及标签
        QuestionWithUserInfoVO questionWithUserInfoVO =
                getQuestionWithUserInfoVO(question);

        //查询选项信息
        if (question.getQuestionType() != 0){
            LambdaQueryWrapper<QuestionItem> questionItemLambdaQueryWrapper = new LambdaQueryWrapper<>();
            questionItemLambdaQueryWrapper.eq(QuestionItem::getQuestionId,id);
            List<QuestionItem> questionItems = questionItemService.list(questionItemLambdaQueryWrapper);
            questionDetailVO.setQuestionItem(questionItems);

            //查询答案
            LambdaQueryWrapper<QuestionAnswer> questionAnswerLambdaQueryWrapper = new LambdaQueryWrapper<>();
            questionAnswerLambdaQueryWrapper.eq(QuestionAnswer::getQuestionId,id);
            List<String> answerList = questionAnswerService.list(questionAnswerLambdaQueryWrapper).stream().map(QuestionAnswer::getQuestionItemNum).collect(Collectors.toList());
            questionDetailVO.setQuestionAnswer(answerList);
        }

        BeanUtils.copyProperties(question,questionDetailVO);
        BeanUtils.copyProperties(questionWithUserInfoVO,questionDetailVO);


        return questionDetailVO;
    }

    @Override
    @Transactional
    public boolean updateQuestion(AddQuestionParamVO updateQuestion) {
        //查询题目类型
        Integer questionType = updateQuestion.getQuestionType();

        //保存题目基本信息（单选题答案直接存入）
        Question question = new Question();
        BeanUtils.copyProperties(updateQuestion,question);
        boolean save = updateById(question);
        if (!save){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"修改失败");
        }

        //获取题目id
        Long id = updateQuestion.getId();

        //保存题目标签
        List<Integer> tags = updateQuestion.getTags();
        List<QuestionTags> tagsList = tags.stream().map(tag -> {
            QuestionTags questionTags = new QuestionTags();
            questionTags.setQuestionId(updateQuestion.getId());
            questionTags.setTagsId(tag);
            return questionTags;
        }).collect(Collectors.toList());
        deleteTagsItemAndAnswer(id,questionType);
        boolean b = questionTagsService.saveBatch(tagsList);
        if (!b){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"修改失败");
        }

        //简答题
        if (questionType == 0){
            return true;
        }
        //其他题目
        //单选题
        if (questionType == 1){
            SingleOptionAndAnswerVO singleParams = updateQuestion.getSingleParams();
            if (singleParams == null){
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"题目选项不能为空");
            }
            //修改题目答案
            String answer = singleParams.getAnswer();
            QuestionAnswer questionAnswer = new QuestionAnswer();
            questionAnswer.setQuestionId(id);
            questionAnswer.setQuestionItemNum(answer);
            boolean saveAnswer = questionAnswerService.save(questionAnswer);
            if (!saveAnswer){
                throw new BusinessException(ErrorCode.OPERATION_ERROR,"修改失败");
            }
            //修改题目选项
            return addQuestionItem(id, singleParams.getOptions());
        }


        MultipleOptionAndAnswerVO multipleParams = updateQuestion.getMultipleParams();
        if (multipleParams == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题目选项不能为空");
        }
        //添加题目答案
        List<String> answerList = multipleParams.getAnswer();
        List<QuestionAnswer> questionAnswerList = answerList.stream().map(answer -> {
            QuestionAnswer questionAnswer = new QuestionAnswer();
            questionAnswer.setQuestionId(id);
            questionAnswer.setQuestionItemNum(answer);
            return questionAnswer;
        }).collect(Collectors.toList());
        boolean saveBatch = questionAnswerService.saveBatch(questionAnswerList);
        if (!saveBatch) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "添加题目失败");
        }

        //添加选项
        return addQuestionItem(id, multipleParams.getOptions());
    }


    private void deleteTagsItemAndAnswer(Long id,Integer type) {
        //删除标签
        LambdaQueryWrapper<QuestionTags> questionTagsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        questionTagsLambdaQueryWrapper.eq(QuestionTags::getQuestionId, id);
        boolean remove = questionTagsService.remove(questionTagsLambdaQueryWrapper);
        if (!remove){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"操作失败");
        }
        if (type == 0){
            return;
        }
        //删除答案和选
        LambdaQueryWrapper<QuestionAnswer> questionAnswerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        questionAnswerLambdaQueryWrapper.eq(QuestionAnswer::getQuestionId, id);
        boolean remove1 = questionAnswerService.remove(questionAnswerLambdaQueryWrapper);
        if (!remove1){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"操作失败");
        }
        LambdaQueryWrapper<QuestionItem> questionItemLambdaQueryWrapper = new LambdaQueryWrapper<>();
        questionItemLambdaQueryWrapper.eq(QuestionItem::getQuestionId, id);
        boolean remove2 = questionItemService.remove(questionItemLambdaQueryWrapper);
        if (!remove2){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"操作失败");
        }
    }

    @Override
    @Transactional
    public boolean deleteQuestion(Long id) {
        //根据题目id删除评论
        LambdaQueryWrapper<Comment> commentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        commentLambdaQueryWrapper.eq(Comment::getQuestionId,id);
        List<Comment> list = commentService.list(commentLambdaQueryWrapper);

        if (list.size() != 0){
            boolean removeComment = commentService.remove(commentLambdaQueryWrapper);
            if (!removeComment){
                throw new BusinessException(ErrorCode.OPERATION_ERROR,"删除评论步骤失败");
            }
        }

        //根据博客id删除喜欢
        LambdaQueryWrapper<QuestionLike> likesLambdaQueryWrapper = new LambdaQueryWrapper<>();
        likesLambdaQueryWrapper.eq(QuestionLike::getQuestionId,id);
        List<QuestionLike> questionLikes = questionLikeService.list(likesLambdaQueryWrapper);
        if (questionLikes.size() != 0){
            boolean removeLikes = questionLikeService.remove(likesLambdaQueryWrapper);
            if (!removeLikes){
                throw new BusinessException(ErrorCode.OPERATION_ERROR,"删除喜欢步骤失败");
            }
        }

        //删除题目
        Question question = getById(id);
        //删除标签，选项，答案
        deleteTagsItemAndAnswer(id,question.getQuestionType());

        return removeById(id);
    }


    @Override
    public AddQuestionParamVO queryQuestionById(Long id) {

        Question question = getById(id);
        Integer questionType = question.getQuestionType();

        AddQuestionParamVO addQuestionParamVO = new AddQuestionParamVO();
        BeanUtils.copyProperties(question,addQuestionParamVO);

        //查询标签信息
        //查询当前题目的所有标签id
        List<Tags> tags = getTagsList(question);
        List<Integer> tagsIdList = tags.stream().map(Tags::getId).collect(Collectors.toList());

        //查询选项信息
        if (question.getQuestionType() != 0){
            LambdaQueryWrapper<QuestionItem> questionItemLambdaQueryWrapper = new LambdaQueryWrapper<>();
            questionItemLambdaQueryWrapper.eq(QuestionItem::getQuestionId,id);
            List<QuestionItem> questionItems = questionItemService.list(questionItemLambdaQueryWrapper);
            List<String> items = questionItems.stream().map(QuestionItem::getContent).collect(Collectors.toList());

            //查询答案
            LambdaQueryWrapper<QuestionAnswer> questionAnswerLambdaQueryWrapper = new LambdaQueryWrapper<>();
            questionAnswerLambdaQueryWrapper.eq(QuestionAnswer::getQuestionId,id);

            MultipleOptionAndAnswerVO multipleOptionAndAnswerVO = new MultipleOptionAndAnswerVO();
            SingleOptionAndAnswerVO singleOptionAndAnswerVO = new SingleOptionAndAnswerVO();
            singleOptionAndAnswerVO.setOptions(items);
            multipleOptionAndAnswerVO.setOptions(items);

            if (questionType == 1){
                QuestionAnswer questionAnswer = questionAnswerService.getOne(questionAnswerLambdaQueryWrapper);
                singleOptionAndAnswerVO.setAnswer(questionAnswer.getQuestionItemNum());
                ArrayList<String> ans = new ArrayList<>();
                ans.add(questionAnswer.getQuestionItemNum());
                multipleOptionAndAnswerVO.setAnswer(ans);
            }else{
                List<String> answerList = questionAnswerService.list(questionAnswerLambdaQueryWrapper).stream().map(QuestionAnswer::getQuestionItemNum).collect(Collectors.toList());
                multipleOptionAndAnswerVO.setAnswer(answerList);
                singleOptionAndAnswerVO.setAnswer(answerList.get(0));
            }
            addQuestionParamVO.setSingleParams(singleOptionAndAnswerVO);
            addQuestionParamVO.setMultipleParams(multipleOptionAndAnswerVO);
        }

        addQuestionParamVO.setTags(tagsIdList);

        return addQuestionParamVO;
    }

    @Override
    public List<AddQuestionParamVO> queryQuestionWithItemByIds(List<Long> ids) {
        return ids.stream().map(this::queryQuestionById).collect(Collectors.toList());
    }

    @Override
    public List<QuestionWithUserInfoVO> getMyStartQuestion() {
        Long id = UserHolder.getUser().getId();

        LambdaQueryWrapper<QuestionLike> questionLikeLambdaQueryWrapper= new LambdaQueryWrapper<>();
        questionLikeLambdaQueryWrapper.eq(QuestionLike::getUserId,id);

        List<QuestionLike> questionLikeList = questionLikeService.list(questionLikeLambdaQueryWrapper);
        if (questionLikeList==null||questionLikeList.isEmpty()){
            return Collections.emptyList();
        }
        List<Long> questionIdList = questionLikeList
                .stream()
                .map(QuestionLike::getQuestionId)
                .collect(Collectors.toList());

        return questionIdList.stream().map(item -> {
            Question question = getById(item);
            QuestionWithUserInfoVO questionWithUserInfoVO = getQuestionWithUserInfoVO(question);
            return questionWithUserInfoVO;
        }).collect(Collectors.toList());
    }

    /**
     * 获取题目标签
     * @param question
     * @return
     */
    private List<Tags> getTagsList(Question question) {
        LambdaQueryWrapper<QuestionTags> tagsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        tagsLambdaQueryWrapper.eq(QuestionTags::getQuestionId, question.getId());
        List<QuestionTags> list = questionTagsService.list(tagsLambdaQueryWrapper);

        List<Integer> tagsList = list.stream().map(QuestionTags::getTagsId).collect(Collectors.toList());
        return tagsService.listByIds(tagsList);
    }

    /**
     * 添加问题选项到数据库
     * @param id 题目id
     * @param optionsList 选项信息
     * @return 是否添加成功
     */
    private Boolean addQuestionItem(Long id, List<String> optionsList) {
        List<String> options = optionsList;

        List<QuestionItem> questionItemList = options.stream().map(item -> {
            QuestionItem questionItem = new QuestionItem();
            questionItem.setQuestionId(id);
            questionItem.setContent(item);

            //单选题
            char i = (char) (65 + options.indexOf(item));
            questionItem.setNum(Character.toString(i));
            return questionItem;
        }).collect(Collectors.toList());

        boolean saveBatch = questionItemService.saveBatch(questionItemList);
        if (!saveBatch){
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"添加题目失败");
        }

        return true;
    }
}




